use bytes::{Buf, BufMut, BytesMut};
use crate::error::{RpcError};

pub struct BytesMutHelp;

impl BytesMutHelp {

    pub(crate) fn write_string(bytes_mut: &mut BytesMut, str: String) {
        let bytes = str.into_bytes();
        let length = bytes.len();
        bytes_mut.put_u32(bytes.len() as u32);
        if length > 0 {
            bytes_mut.put_slice(&bytes[..]);
        }
    }

    pub(crate) fn write_str(bytes_mut: &mut BytesMut, str: &str) {
        let bytes = str.as_bytes();
        let length = bytes.len();
        bytes_mut.put_u32(bytes.len() as u32);
        if length > 0 {
            bytes_mut.put_slice(&bytes[..]);
        }

    }

    pub(crate) fn read_string(bytes_mut: &mut BytesMut) -> Result<String, RpcError> {
        let length =bytes_mut.get_u32();
        let bytes = bytes_mut.copy_to_bytes(length as usize);
        let str = String::from_utf8(bytes.into())?;
        Ok(str)
    }

    pub(crate) fn write_option_string(bytes_mut: &mut BytesMut, str: Option<String>) {
        match str {
            None => {
                bytes_mut.put_u32(0);
            }
            Some(str) => {
                let bytes = str.as_bytes();
                let length = bytes.len();
                bytes_mut.put_u32(bytes.len() as u32);
                if length > 0 {
                    bytes_mut.put_slice(bytes);
                }
            }
        }

    }

    pub(crate) fn read_option_string(bytes_mut: &mut BytesMut) -> Result<Option<String>, RpcError> {
        let length =bytes_mut.get_u32();
        if length > 0 {
            let bytes = bytes_mut.copy_to_bytes(length as usize);
            let str = String::from_utf8(bytes.into())?;
            return Ok(Some(str));
        }
        Ok(None)
    }
}

#[test]
fn read_string_test() {
    let mut bytes_mut = BytesMut::new();
    let data = "hello world".to_string();
    BytesMutHelp::write_string(&mut bytes_mut, data.clone());
    let value = BytesMutHelp::read_string(&mut bytes_mut).unwrap();
    assert_eq!(value, data);
}

#[test]
fn read_option_str_test() {
    let mut bytes_mut = BytesMut::new();
    let data = Some("hello world".to_string());
    BytesMutHelp::write_option_string(&mut bytes_mut, data.clone());
    let value = BytesMutHelp::read_option_string(&mut bytes_mut).unwrap();
    assert_eq!(value, data);
}